/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.jdo.annotations.Index;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;

/**
 *
 * @author Gerben Feenstra
 */
@NamedQueries(value = {
    @NamedQuery(name = ProductionUnit.Q_FIND_ALL_PRODUCTION_UNITS, query = "select p from ProductionUnit p"),
    @NamedQuery(name = ProductionUnit.Q_FIND_ALL_PRODUCTION_UNITS_BY_DATE, query = "select p from ProductionUnit p where :date >= p.startDate and :date <= p.endDate")
})
@Entity
@Table(name = "PRODUCTION_UNIT")
public class ProductionUnit extends Bean implements Serializable, Persistable {

    public static final String Q_FIND_ALL_PRODUCTION_UNITS = "findAllProductionUnits";
    public static final String Q_FIND_ALL_PRODUCTION_UNITS_BY_DATE = "findAllProductionUnitsByDate";
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private long id;
    
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "FIELDPLAN_ID")
    private FieldPlan fieldPlan;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "productionUnit")
    private List<PartField> partFields;
    
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "productionUnit")
    private List<Operation> operations;
    
    @Column(name = "CROP")
    private String crop;

    @Column
    @Index
    @Temporal(TemporalType.DATE)
    private Date startDate;
    
    @Column
    @Index
    @Temporal(TemporalType.DATE)
    private Date endDate;
    
    private static final AppLogger LOG = AppLogFactory.getLogger(Surface.class);
        
    @Override
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    public String getCrop() {
        return crop;
    }

    public void setCrop(String crop) {
        String old = this.crop;
        this.crop = crop;
        getPropertyChangeSupport().firePropertyChange("crop", old, crop);
    }

    public FieldPlan getFieldPlan() {
        return fieldPlan;
    }

    public void setFieldPlan(FieldPlan fieldPlan) {
        FieldPlan old = this.fieldPlan;
        this.fieldPlan = fieldPlan;
        getPropertyChangeSupport().firePropertyChange("fieldPlan", old, fieldPlan);
    }
    
    public List<PartField> getPartFields() {
        if(partFields == null){
            partFields = new ArrayList<PartField>();
        }
        return partFields;
    }

    public List<Operation> getOperations() {
        if(operations == null){
            operations = new ArrayList<Operation>();
        }
        return operations;
    }
    
    /**
     * Calculates Acreage using the underlying partFields.
     * @return Calculated acreage
     */
     public Double getAcreage() {
        double acreage = 0d;
        for(PartField pField : partFields){
            acreage += pField.getAcreage();
        }
        return acreage;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        if(endDate == null || (startDate == null || endDate.compareTo(startDate) > 0))
        {
            Date old = this.endDate;
            this.endDate = endDate;
            getPropertyChangeSupport().firePropertyChange("endDate", old, endDate);
            fireUndoableEvent("endDate", this, old, endDate);
        }
        else{
            // Todo: temp debug, should display in message window
            LOG.warning("surface.setenddate");
            // http://netbeans.org/bugzilla/show_bug.cgi?id=188880
            //throw new DateSetException("Enddate should be > startdate");
        }
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        if(startDate == null || (endDate == null || startDate.compareTo(endDate)< 0)){
            Date old = this.startDate;
            this.startDate = startDate;
            getPropertyChangeSupport().firePropertyChange("startDate", old, startDate);
            fireUndoableEvent("startDate", this, old, startDate);
        }
        else{
            LOG.warning("surface.setstartdate");
            // http://netbeans.org/bugzilla/show_bug.cgi?id=188880
            //throw new DateSetException("Startdate should be < enddate");
        }
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ProductionUnit other = (ProductionUnit) obj;
        if (this.id != other.id) {
            return false;
        }
        if (this.fieldPlan != other.fieldPlan && (this.fieldPlan == null || !this.fieldPlan.equals(other.fieldPlan))) {
            return false;
        }
        if ((this.crop == null) ? (other.crop != null) : !this.crop.equals(other.crop)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 17 * hash + (int) (this.id ^ (this.id >>> 32));
        hash = 17 * hash + (this.fieldPlan != null ? this.fieldPlan.hashCode() : 0);
        hash = 17 * hash + (this.crop != null ? this.crop.hashCode() : 0);
        return hash;
    }
    
    
    /**
     * Culture builder class
     *
     * usage: Culture culture = new Culture.Builder().setName("someName").build();
     *
     */
    public static class Builder {

        ProductionUnit productionUnit;
        
        public Builder() {
            productionUnit = new ProductionUnit();
        }

        public Builder setCrop(String crop) {
            productionUnit.setCrop(crop);
            return this;
        }

        public Builder setFieldPlan(FieldPlan fieldPlan) {
            productionUnit.setFieldPlan(fieldPlan);
            return this;
        }

        public Builder setName(String name) {
            productionUnit.setName(name);
            return this;
        }

        public Builder setEndDate(Date endDate) {
            productionUnit.setEndDate(endDate);
            return this;
        }

        public Builder setStartDate(Date startDate) {
            productionUnit.setStartDate(startDate);
            return this;
        }

        public Builder addPartField(PartField field) {
            productionUnit.getPartFields().add(field);
            return this;
        }

        public ProductionUnit build() {
            return productionUnit;
        }
    }
}
